package com.ecoolex.chinadutyfree.retailer.core.manager;

import java.time.Instant;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ecoolex.chinadutyfree.retailer.core.dao.DirectMailGoodsProductDAO;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoods;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoodsProduct;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoodsProduct.Column;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoodsProductExample;
import com.ecoolex.chinadutyfree.retailer.entity.GoodsProduct;
import com.ecoolex.chinadutyfree.retailer.enums.DirectMailGoodsProductStatus;
import com.ecoolex.chinadutyfree.retailer.enums.DirectMailGoodsStatus;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.Ternary;


@Service
public class DirectMailGoodsProductManager {

    @Autowired
    private DirectMailGoodsProductDAO dao;

    @Autowired
    private DirectMailGoodsManager directMailGoodsManager;

    @Autowired
    private GoodsProductManager goodsProductManager;

    @Autowired
    private DirectMailGoodsShoppingCartManager directMailGoodsShoppingCartManager;

    private void verify(DirectMailGoodsProduct record) {
        BizAssert.isTrue(Check.notNullAndGtZero(record.getRetailPrice()), ResultCode.VERIFY.build(10), "零售价格必须大于0");
        BizAssert.isTrue(Check.notNullAndGteZero(record.getStockNumber()), ResultCode.VERIFY.build(11), "库存数量必须大于等于0");
    }

    @Transactional
    public DirectMailGoodsProduct add(DirectMailGoods goods, DirectMailGoodsProduct mailGoodsProduct, String createUser) {
        verify(mailGoodsProduct);
        GoodsProduct product = goodsProductManager.getById(mailGoodsProduct.getProductId());
        BizAssert.isTrue(Check.notNull(product), ResultCode.VERIFY.build(12), "商品产品为空");
        BizAssert.isTrue(Check.eq(goods.getGoodsId(), product.getGoodsId()),
            ResultCode.VERIFY.build(13),
            "产品与直邮商品的商品不一致");
        BizAssert.isTrue(existProductByDirectMailGoods(goods.getDirectMailGoodsId(), mailGoodsProduct.getProductId()),
            ResultCode.VERIFY.build(14),
            "直邮商品中已经存在该商品");

        mailGoodsProduct.setDirectMailGoodsId(goods.getDirectMailGoodsId());
        mailGoodsProduct.setGoodsId(goods.getGoodsId());
        mailGoodsProduct.setProductId(product.getProductId());
        mailGoodsProduct.setSpecNames(product.getSpecNames());
        mailGoodsProduct.setSpecSorting(product.getSpecSorting());
        mailGoodsProduct.setUsedStockNumber(0);
        mailGoodsProduct.setSoldNumber(0);
        mailGoodsProduct.setStatus(DirectMailGoodsProductStatus.NORMAL.real());
        mailGoodsProduct.setDeleted(DirectMailGoodsProduct.NOT_DELETED);
        mailGoodsProduct.setCreateUser(createUser);
        mailGoodsProduct.setCreateTime(Date.from(Instant.now()));
        mailGoodsProduct.setUpdateUser(createUser);
        mailGoodsProduct.setUpdateTime(Date.from(Instant.now()));

        dao.insert(mailGoodsProduct);

        BizAssert.isTrue(goodsProductManager.resetUsedStockNumber(product, createUser),
            ResultCode.BIZ.build(1),
            "扣除商品库库存失败,库存不足");

        return mailGoodsProduct;
    }

    @Transactional
    public DirectMailGoodsProduct update(DirectMailGoodsProduct mailGoodsProduct, String updateUser) {
        verify(mailGoodsProduct);

        GoodsProduct product = goodsProductManager.getById(mailGoodsProduct.getProductId());
        BizAssert.isTrue(Check.notNull(product), ResultCode.VERIFY.build(12), "商品产品为空");

        // 更新数据
        mailGoodsProduct.setUpdateUser(updateUser);
        mailGoodsProduct.setUpdateTime(Date.from(Instant.now()));

        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailProductIdEqualTo(mailGoodsProduct.getDirectMailProductId())
            // 必须大于等于已经使用的库存数量, 否则修改失败
            .andUsedStockNumberLessThanOrEqualTo(mailGoodsProduct.getStockNumber()).andDeletedEqualTo(
                DirectMailGoodsProduct.NOT_DELETED);

        int row = dao.updateByExampleSelective(mailGoodsProduct,
            example,
            Column.excludes(Column.directMailGoodsId,
                Column.goodsId,
                Column.productId,
                Column.specNames,
                Column.specSorting,
                Column.usedStockNumber,
                Column.soldNumber,
                Column.status,
                Column.deleted,
                Column.createUser,
                Column.createTime));
        BizAssert.isTrue(row == 1, ResultCode.BIZ.build(1), "更新失败,库存必须大于等于已使用库存");

        BizAssert.isTrue(goodsProductManager.resetUsedStockNumber(product, updateUser),
            ResultCode.BIZ.build(1),
            "更新商品库产品库存失败,库存可能不足");

        return mailGoodsProduct;
    }

    @Transactional
    public void delete(DirectMailGoodsProduct mailGoodsProduct, String updateUser) {
        DirectMailGoods goods = directMailGoodsManager.getById(mailGoodsProduct.getDirectMailGoodsId());
        // BizAssert.isTrue(Check.notNull(goods), ResultCode.VERIFY.build(10), "直销商品为空");
        // 是上线状态
        if (Check.notNull(goods) && DirectMailGoodsStatus.RELEASE.equal(goods.getStatus())) {
            // 上线状态不能删除最后一个商品
            BizAssert.isTrue(countByGoodsIds(goods.getDirectMailGoodsId()) > 0,
                ResultCode.VERIFY.build(2),
                "直销商品上线状态,最后一个商品无法删除");
        }

        mailGoodsProduct.setDeleted(DirectMailGoodsProduct.IS_DELETED);
        mailGoodsProduct.setUpdateUser(updateUser);
        mailGoodsProduct.setUpdateTime(Date.from(Instant.now()));
        dao.updateByPrimaryKeySelective(mailGoodsProduct, Column.deleted, Column.updateUser, Column.updateTime);

        GoodsProduct product = goodsProductManager.getById(mailGoodsProduct.getProductId());
        if (Check.notNull(product) && DirectMailGoodsProductStatus.NORMAL.equal(mailGoodsProduct.getStatus())
            && Check.notNullAndGtZero(mailGoodsProduct.getStockNumber())) {
            BizAssert.isTrue(goodsProductManager.resetUsedStockNumber(product, updateUser),
                ResultCode.BIZ.build(1),
                "更新商品库产品库存失败");
        }
        // 作废购物车中的商品
        directMailGoodsShoppingCartManager.invalidByDirectMailProductId(mailGoodsProduct.getDirectMailProductId(),
            updateUser);
    }

    public boolean addUsedStockNumber(Integer directMailGoodsProductId, Integer buyNumber, String updateUser) {
        return dao.addUsedStockNumber(directMailGoodsProductId, buyNumber, updateUser) == 1;
    }

    public boolean subtractUsedStockNumber(Integer directMailGoodsProductId, Integer buyNumber, String updateUser) {
        return dao.subtractUsedStockNumber(directMailGoodsProductId, buyNumber, updateUser) == 1;
    }

    public boolean addSoldNumber(Integer directMailGoodsProductId, Integer buyNumber, String updateUser) {
        return dao.addSoldNumber(directMailGoodsProductId, buyNumber, updateUser) == 1;
    }

    public void updateProductInfo(GoodsProduct product, String updateUser) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andProductIdEqualTo(product.getProductId()).andStatusEqualTo(
            DirectMailGoodsProductStatus.NORMAL.real()).andDeletedEqualTo(DirectMailGoodsProduct.NOT_DELETED);

        DirectMailGoodsProduct record = new DirectMailGoodsProduct();
        record.setSpecNames(product.getSpecNames());
        record.setSpecSorting(product.getSpecSorting());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        dao.updateByExampleSelective(record,
            example,
            Column.specNames,
            Column.specSorting,
            Column.updateUser,
            Column.updateTime);
    }

    public void deleteProduct(GoodsProduct product, String updateUser) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andProductIdEqualTo(product.getProductId()).andStatusEqualTo(
            DirectMailGoodsProductStatus.NORMAL.real()).andDeletedEqualTo(DirectMailGoodsProduct.NOT_DELETED);

        DirectMailGoodsProduct record = new DirectMailGoodsProduct();
        record.setStatus(DirectMailGoodsProductStatus.OFFLINE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        dao.updateByExampleSelective(record, example, Column.status, Column.updateUser, Column.updateTime);
    }

    public DirectMailGoodsProduct getById(Integer directMailProductId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(directMailProductId, DirectMailGoodsProduct.NOT_DELETED);
    }

    public List<DirectMailGoodsProduct> queryAllStatusByDirectMailGoodsId(Integer directMailGoodsId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andDeletedEqualTo(
            DirectMailGoodsProduct.NOT_DELETED);
        example.orderBy(Column.status.desc(), Column.specSorting.asc());
        return dao.selectByExample(example);
    }

    public List<DirectMailGoodsProduct> queryNormalByDirectMailGoodsId(Integer directMailGoodsId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andStatusEqualTo(
            DirectMailGoodsProductStatus.NORMAL.real()).andDeletedEqualTo(DirectMailGoodsProduct.NOT_DELETED);
        example.orderBy(Column.status.desc(), Column.specSorting.asc());
        return dao.selectByExample(example);
    }

    public boolean existProductByDirectMailGoods(Integer directMailGoodsId, Integer productId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andProductIdEqualTo(
            productId).andDeletedEqualTo(DirectMailGoodsProduct.NOT_DELETED);
        return dao.countByExample(example) < 1;
    }

    public long countByGoodsIdAndStatus(Integer directMailGoodsId, DirectMailGoodsProductStatus status) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andStatusEqualTo(
            status.real()).andDeletedEqualTo(DirectMailGoodsProduct.NOT_DELETED);
        return dao.countByExample(example);
    }

    public long countByGoodsIds(Integer directMailGoodsId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andDeletedEqualTo(
            DirectMailGoodsProduct.NOT_DELETED);
        return dao.countByExample(example);
    }

    public void deleteByDirectMailGoodsId(Integer directMailGoodsId, String updateUser) {
        queryAllStatusByDirectMailGoodsId(directMailGoodsId).forEach(d -> delete(d, updateUser));
    }

    public Long sumStockNumberByDirectMailGoodsId(Integer directMailGoodsId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andStatusEqualTo(
            DirectMailGoodsProductStatus.NORMAL.real()).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        Long result = dao.sumStockNumberByExample(example);
        return Ternary.notNull(result, 0L);
    }

    public Long sumUsedStockNumberByDirectMailGoodsId(Integer directMailGoodsId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andStatusEqualTo(
            DirectMailGoodsProductStatus.NORMAL.real()).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        Long result = dao.sumUsedStockNumberByExample(example);
        return Ternary.notNull(result, 0L);
    }

    public Long sumSoldNumberByDirectMailGoodsId(Integer directMailGoodsId) {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDirectMailGoodsIdEqualTo(directMailGoodsId).andStatusEqualTo(
            DirectMailGoodsProductStatus.NORMAL.real()).andDeletedEqualTo(GoodsProduct.NOT_DELETED);
        Long result = dao.sumSoldNumberByExample(example);
        return Ternary.notNull(result, 0L);
    }

    public List<DirectMailGoodsProduct> queryList() {
        DirectMailGoodsProductExample example = new DirectMailGoodsProductExample();
        example.createCriteria().andDeletedEqualTo(DirectMailGoodsProduct.NOT_DELETED);
        return dao.selectByExample(example);
    }
}